/**
 * std::future 和 std::promise 配合使用
 * std::promise 提供了一种手动设置值的方式，可以在设置之后通过std::future对象进行读取
 * std::future可以读取异步函数的返回值，但是需要等待就绪。
 * std::promise提供了一种手动让std::future就绪的方式。
 * 
 * 关键特性:
 * 1.一对一绑定：一个 std::promise 只能与一个 std::future 关联，且 get_future() 只能调用一次（多次调用会抛出异常）。
 * 2.状态转移：当调用 set_value() 或 set_exception() 后，promise 的状态变为 "就绪"（ready），此时 future::get() 会立即返回结果（或抛出异常）；
 * 若未设置值就销毁 promise，会自动设置一个 std::future_error 异常，避免消费者线程无限等待。
 * 3.不可拷贝，可移动：std::promise 禁止拷贝（确保资源唯一），但允许移动（可在线程间传递所有权）。
 */

#include <iostream>
#include <future>
#include <chrono>
#include <thread>

void task(std::promise<int> promise)
{
    int sum = 0;
    for(int i = 0; i < 10; i++)
        sum += i;
    
    std::this_thread::sleep_for(std::chrono::seconds(2));

    promise.set_value(sum);
}

int add(int num1, int num2)
{
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return num1+num2;
}

int main()
{
    std::promise<int> result_promise;
    std::future<int> result_future = result_promise.get_future();

    
    /**
     * Q: 为什么这个lambda表达式可以直接使用add函数，而不需要捕获？
     * A: lambda 只需要捕获局部作用域中的变量，对于全局作用域的函数或变量，可直接访问，无需捕获。
     * 
     * lambda 捕获的作用:
     * lambda 表达式的捕获列表（[] 中的内容）用于获取当前作用域中的局部变量（包括函数参数、局部定义的变量等）的访问权。
     * 例如，如果要在 lambda 中使用 main 函数里定义的局部变量 x，就需要通过 [x] 或 [&x] 捕获.
     * 
     * add 函数的性质:
     * 代码中的 add 是一个全局函数（定义在 main 之外），它不属于任何局部作用域，而是具有全局可见性。
     * 在 C++ 中，全局函数（以及全局变量、类的静态成员等）属于全局作用域，可以被程序中的任何地方直接访问，无需通过捕获获取权限。
     * 
     * 类比理解:
     * 这就像在任何函数中都能直接调用 printf（标准库的全局函数）一样，lambda 作为一个可调用对象，自然也能直接访问全局可见的 add 函数，无需额外捕获。
     * 
     */
    // std::thread task_thread(task, std::move(result_promise));
    std::thread task_thread([&result_promise](){
        int ret = add(1, 2);
        result_promise.set_value(ret);
    });

    // 执行其他操作
    for(int i = 1; i < 11; i++)
    {
        std::cout << i << " 主线程中其他操作执行中..." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    int ret = result_future.get();
    std::cout << "异步任务执行的结果为: " << ret << std::endl;

    if(task_thread.joinable())
    {
        task_thread.join();
    }

    return 0;
}

int add(int num1, int num2)
{
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return num1+num2;
}